docs(driver-sql): the lookup arm no longer claims a platform id is 26 characters - #16116
Conversation
… characters
`createColumn`'s `case 'lookup': case 'user':` arm argued that `maxLength`
must not bind a reference column, and backed it with a worked example: a
26-character ULID refused by `varchar(20)` as `ERROR 1406 Data too long`.
That number is not this platform's, and at the real one the example did not
hold — 16 characters fit in `varchar(20)`.
Measured, not inferred:
- `DEFAULT_ID_LENGTH` is 16, and `git log -p --follow` over the whole life
of the file yields exactly one `+const DEFAULT_ID_LENGTH` line and no `-`
line: it has never been anything else. The id shape never moved, so
neither site was residue.
- No ULID is minted anywhere in the repo. `git grep -rni ulid` excluding
the lockfile returns 0, with `nanoid` as the firing control (50).
- Driving the real `SqlDriver` against SQLite: a write supplying no id gets
a 16-character nanoid; a write supplying one has it stored verbatim at
whatever width the caller chose (10-, 17- and 18-character ids all landed
unaltered). Nothing on this path bounds an id's width at all.
The argument the sentence supports is unchanged and is now stated in the
stronger form the measurement licenses: an id's width is not a fixed number,
so no `maxLength` can be known to fit one. Nothing about what the driver
mints changes; the diff is comments only.
The sibling comment in `sql-driver-string-maxlength-varchar.test.ts` carried
the same number and moves with it. Four `packages/cli` sites cite this arm by
name for it and are filed as #16114 rather than fixed here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8b4325de538b4cecbf5f3847d4aacb8f27ad01f1 && git checkout 8b4325de538b4cecbf5f3847d4aacb8f27ad01f1
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a4816a79d0396d0fd10696cdf95d66e55aef92d3 d337f421d68c485050ea56bb4b2b28d2c26d705d && git checkout -B drift-repro a4816a79d0396d0fd10696cdf95d66e55aef92d3 && git merge --no-ff d337f421d68c485050ea56bb4b2b28d2c26d705d
node scripts/docs-audit/affected-docs.mjs --json a4816a79d0396d0fd10696cdf95d66e55aef92d3 |
Fixes #15522
Deliverable 1 first — the reading, before either number moved
The card and the claim both forbade touching either number until the id's provenance was established, and offered two readings. Measured on
origin/main64011dd3f: neither holds, and the third answer is what shipped.git grep -rni ulidrepo-wide, lockfile excludednanoidon the same instrument → 50 (fires)git log -p --followoversql-driver.ts, allconst DEFAULT_ID_LENGTHlines+line (= 16), no-line everDEFAULT_ID_LENGTHacross every driverdriver-sql16 ·driver-mongodb16 ·driver-turso16driver-memorymintsname-timestamp-counter— a different shape entirelynanoid(insql-driver.tselse if (id === undefined)fallback branchengine.tshands the row todriver.createunaltered; its only generator isgenerateEventUuidforDataEvent.idAnd the firing empirical control — the real
SqlDriverdriven against SQLite, one write supplying an id and one not:DEFAULT_ID_LENGTHhas been 16 for the whole life of the file, and the sentence was written 2026-08-24 (c49afd088), after the constant was already 16. Neither site is residue.varchar(20), so theERROR 1406 Data too longthe comment promised would not have fired.⇒ The STOP CONDITION is not reached. The fix touches prose only;
DEFAULT_ID_LENGTHstays 16 and all three mint sites are untouched. No data-shape change, no manual floor.The argument is kept, and stated in the stronger form the measurement licenses
The sentence exists to argue that
maxLengthmust not bind a reference column. That argument never depended on 26 — and it is stronger without it: an id's width is not a fixed number at all. The driver mints 16 when the caller supplies none, and stores a supplied id verbatim at whatever width the caller chose, so nomaxLengthcan be known to fit one.Scope, and the one bounded in-place fix
packages/drivers/driver-sql/src/sql-driver.ts— the card's site, in thecase 'lookup': case 'user':arm.packages/drivers/driver-sql/src/sql-driver-string-maxlength-varchar.test.ts— the bounded in-place fix, named here with its evidence. The same sentence, same package, same gate family, same defect class; it is a comment, not an asserted value (the assertion isexpect(shapes.a_lookup).toBe('varchar(255)')and is untouched). Leaving it would have shipped a driver whose own pin test's comment contradicted it.git grep "platform id is 26 characters", repo-wide): after this PR the phrase survives at fourpackages/clisource sites and two CHANGELOG entries. The CLI four are a different package and a different verification surface, so they are ⛔ filed as [finding] fourpackages/clisites cite driver-sql's lookup arm for "a platform id is 26 characters" — the platform mints 16, and stores a supplied id at any width #16114 rather than fixed here; the CHANGELOGs are historical records and are ⛔ not editable.⭐ Those four each cite this driver arm by name as their authority. That is exactly the harm the card was filed on — "a citation waiting to be relied on again" — already realized, in a second package, four times over. The corrected comment now points at #16114 so the chain is traceable.
The card's own measurement, corrected
The card, triage and the claim all recorded two prose sites saying 26. Only one is about ids. The other,
sql-driver.ts* that exactly 26 characters fold, without knowing the server's locale., is about the 26 letters of the ASCII alphabet in the LIKE case-folding map (ASCII_UPPER_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') — a coincidental hit from a baregrep "26 characters", carried forward by three seats. ⛔ It is deliberately untouched.Clause ② —
no, measured on both limbsno. The diff is 37 changed lines, 0 of them non-comment — mechanically checked, every added and removed line matches^[+-]\s*//. Zero executable tokens.DEFAULT_ID_LENGTHand all threenanoid(DEFAULT_ID_LENGTH)sites are byte-untouched.64011dd3f) → mutation confirmed on disk by anchored counts (#155221→0, claim phrase 0→1) and blob hashce45e8de!= HEAD blob4f3fcd6e→ rebuild → restore →git diff HEADempty and blob4f3fcd6e== HEAD blob → rebuild.files[]publishesdist; both declaration filesdist/index.d.tsanddist/index.d.mtsare byte-identical across the ablation (28f610ed), with the head rebuild reproducing the same hash as the control. The only published bytes that move are thesourcesContentblobs insidedist/index.js.map/index.mjs.map— a verbatim copy of the source comment, not a surface.⇒ Comment-only, publishes no API ⇒
skip-changeset, applied additively and read back.Verification — all at
d337f421dpnpm --filter '@objectstack/driver-sql^...' build— VERDICT command-exit 0tsc --noEmit(driver-sql) — exit 0, and--listFilesconfirms both edited files are in the program (1 hit each), so this is a measurement about them and not a vacuous passvitest run src/sql-driver-string-maxlength-varchar.test.ts src/sql-driver-11567-lookup-no-foreign-key.test.ts— 11 passed, 2 skipped (the skips are the live MySQL/Postgres cells, no live server here)check:nul-bytes·check-comment-mask-adoption(+ self-test) ·check-comment-mask-corpus·check-keyed-text-bounds(+ self-test) ·check:driver-conformance·check:tenant-chokepoint·check:test-source-alias·check:cross-package-test-inputs·check:doc-authoring·check:published-files·check:dts-closure·check:objectql-double-limit·check:where-matcher·check:single-claim-paths·check-closing-keyword-parity·check-empty-changeset·check-changeset-no-major·check-changeset-fixed·check-adr-0087-registrationcheck-partof-closing-keyword.mjsfirst returned NOT WIRED (noPR_BODY/PR_NUMBER) — a prerequisite failure and ⛔ not a verdict, so it is not reported as one. Re-run withPR_BODYset to this exact body: exit 0,✓ check:partof-closing-keyword: this PR carries no Part-of/closing-keyword contradiction.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack— provenance line confirmsobjectstack-ai/objectstackatd337f421d, change set 2 paths vs merge base64011dd3f.Generated by Claude Code